package org.quickserver.net.client.pool;

import java.io.IOException;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.quickserver.net.client.BlockingClient;
import org.quickserver.net.client.SocketBasedHost;











public class PooledBlockingClient
{
  private BlockingClient blockingClient;
  private long connectedTime;
  private int handedOutCount;
  private long handedOutSince;
  private long lastActionTime;
  private boolean handedOut;
  private ConcurrentLinkedQueue poolToReturn;
  private PoolableBlockingClient poolableBlockingClient;
  private SocketBasedHost socketBasedHost;
  
  public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append("PooledBlockingClient{");
    sb.append("socketBasedHost:").append(this.socketBasedHost).append(';');
    sb.append("blockingClient:").append(this.blockingClient).append(';');
    sb.append("}");
    return sb.toString();
  }

  
  public PooledBlockingClient(PoolableBlockingClient poolableBlockingClient, SocketBasedHost socketBasedHost) {
    this.poolableBlockingClient = poolableBlockingClient;
    this.socketBasedHost = socketBasedHost;
    
    this.blockingClient = poolableBlockingClient.createBlockingClient(socketBasedHost);
    this.connectedTime = System.currentTimeMillis();
    this.handedOutCount = 0;
    this.handedOutSince = -1L;
    this.handedOut = false;
  }
  
  public void close() {
    if (getBlockingClient() != null) {
      try {
        getBlockingClient().close();
      } catch (IOException ex) {
        Logger.getLogger(BlockingClientPool.class.getName()).log(
            Level.WARNING, "Error closeing: " + ex, ex);
      } 
    }
    this.blockingClient = null;
    this.poolToReturn = null;
    this.poolableBlockingClient = null;
  }
  
  protected boolean replaceBlockingClient() {
    if (this.blockingClient != null) {
      try {
        this.blockingClient.close();
      } catch (IOException ex) {
        Logger.getLogger(PooledBlockingClient.class.getName()).log(
            Level.WARNING, "Error closing : " + ex, ex);
      } 
    }
    
    if (this.poolableBlockingClient != null) {
      this.blockingClient = this.poolableBlockingClient.createBlockingClient(getSocketBasedHost());
      return (this.blockingClient != null);
    } 
    return false;
  }

  
  protected void returnToPool(ConcurrentLinkedQueue poolForInUseHost, ReentrantReadWriteLock lock) {
    if (this.poolToReturn != null) {
      setLastActionTime(System.currentTimeMillis());
      
      Object objToLock = null;
      if (this.poolableBlockingClient.isBlockWhenEmpty()) {
        objToLock = this.poolToReturn;
      }
      
      lock.writeLock().lock();
      try {
        if (poolForInUseHost != null) poolForInUseHost.remove(this); 
        setHandedOut(false);
        this.poolToReturn.add(this);
        this.poolToReturn = null;
      } finally {
        lock.writeLock().unlock();
      } 
      
      if (this.poolableBlockingClient.isBlockWhenEmpty()) {
        synchronized (objToLock) {
          objToLock.notify();
        } 
      }
    } else {
      Logger.getLogger(PooledBlockingClient.class.getName()).log(Level.WARNING, 
          "poolToReturn was null.. will close");
      try {
        getBlockingClient().close();
      } catch (IOException ex) {
        Logger.getLogger(PooledBlockingClient.class.getName()).log(Level.WARNING, "Error " + ex, ex);
      } 
    } 
  }

  
  public BlockingClient getBlockingClient() { return this.blockingClient; }


  
  public void setBlockingClient(BlockingClient blockingClient) { this.blockingClient = blockingClient; }


  
  public long getConnectedTime() { return this.connectedTime; }


  
  public void setConnectedTime(long connectedTime) { this.connectedTime = connectedTime; }


  
  public int getHandedOutCount() { return this.handedOutCount; }


  
  public void setHandedOutCount(int handedOutCount) { this.handedOutCount = handedOutCount; }


  
  public long getHandedOutSince() { return this.handedOutSince; }


  
  public void setHandedOutSince(long handedOutSince) { this.handedOutSince = handedOutSince; }


  
  public boolean isHandedOut() { return this.handedOut; }

  
  public void setHandedOut(boolean handedOut) {
    this.handedOut = handedOut;
    if (handedOut) {
      this.handedOutCount++;
      this.handedOutSince = System.currentTimeMillis();
    } else {
      this.handedOutSince = -1L;
    } 
  }

  
  public ConcurrentLinkedQueue getPoolToReturn() { return this.poolToReturn; }


  
  public void setPoolToReturn(ConcurrentLinkedQueue poolToReturn) { this.poolToReturn = poolToReturn; }


  
  public SocketBasedHost getSocketBasedHost() { return this.socketBasedHost; }


  
  public void setSocketBasedHost(SocketBasedHost socketBasedHost) { this.socketBasedHost = socketBasedHost; }


  
  public long getLastActionTime() { return this.lastActionTime; }


  
  public void setLastActionTime(long lastActionTime) { this.lastActionTime = lastActionTime; }
}
